package com.kabigon.multiverse.component;

import com.kabigon.multiverse.common.api.ResultData;
import com.kabigon.multiverse.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 *
 * @author xu.biao
 * @version v1.0
 * @Package com.kabigon.multiverse.component
 * @data 2022/2/17 22:18
 */
@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
    /**
     * 默认全局异常处理
     * @return ResultData
     */
    @ExceptionHandler(Throwable.class)
    public ResultData<String> exception(Exception e, HttpServletResponse response) {
        log.error("全局异常信息，ex={}", e.getMessage(), e);
        // 未定义的自定义异常
        if (!(e instanceof BaseException)) {
            // 404
            if (e instanceof NoHandlerFoundException) {
                response.setStatus(HttpStatus.NOT_FOUND.value());
                return ResultData.fail(HttpStatus.NOT_FOUND);
            }
            e = BaseException.undefinedException(e);
        }
        BaseException baseException = (BaseException) e;
        response.setStatus(HttpStatus.valueOf(baseException.getCode()).value());
        return ResultData.fail(HttpStatus.valueOf(baseException.getCode()).value(), baseException.getDescription());
    }

    /**
     * 参数异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BindException.class, ConstraintViolationException.class, MethodArgumentNotValidException.class})
    public ResponseEntity<ResultData<String>> handleValidatedException(Exception e) {
        ResultData<String> resp = null;

        if (e instanceof MethodArgumentNotValidException) {
            //
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getBindingResult().getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining("; "))
            );
        } else if (e instanceof ConstraintViolationException) {
            // 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常
            ConstraintViolationException ex = (ConstraintViolationException) e;
            resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getConstraintViolations().stream()
                            .map(ConstraintViolation::getMessage)
                            .collect(Collectors.joining("; "))
            );
        } else if (e instanceof BindException) {
            // 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常
            BindException ex = (BindException) e;
            resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining("; "))
            );
        }

        return new ResponseEntity<>(resp, HttpStatus.BAD_GATEWAY);

    }



}
